﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using ZedGraph;

namespace ChromaticQFX
{
    public partial class MainForm : Form
    {
        #region Member Variables

        public const string BuildNumber = "0.3.0";
        public static MainForm InstanceRef;
        public static string ConfigDir { get { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Chromatic\\"; } }
        public static string ConfigFile { get { return ConfigDir + "historyx.chromatic"; } }
        public static string OldConfigFile { get { return ConfigDir + "history.chromatic"; } }

        public bool IsLoading = false;

        public static QFXHistory import = new QFXHistory();
        public static QFXHistory history = new QFXHistory();

        public DateTime StartDate { get { return dateTimePicker1.Value; } }
        public DateTime EndDate { get { return dateTimePicker2.Value; } }

        #endregion

        #region Common Form Methods

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            Text = "ChromaticQFX (Build " + BuildNumber + ") : A analysis tool for bank account info downloaded in the Quicken QFX file format";
            SetupTooltips();

            SetupActivityGraph();
            SetupRawExpensesGraph();
            SetupRawIncomeGraph();
            SetupCategorizedGraph();
            SetupCategorizedIncome();

            if (!Directory.Exists(ConfigDir))
            {
                try { Directory.CreateDirectory(ConfigDir); }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to create directory : " + ConfigDir, "Unable to create directory in MyDocuments", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            if (File.Exists(OldConfigFile))
            {
                history = QFXHistory.LoadHistory(OldConfigFile);
                history.SaveHistoryX();
                File.Delete(OldConfigFile);
            }

            if (File.Exists(ConfigFile))
            {
                history = QFXHistory.LoadHistoryX();

                IsLoading = true;
                if (history.StartDate != DateTime.MinValue) dateTimePicker1.Value = history.StartDate;
                if (history.EndDate != DateTime.MinValue) dateTimePicker2.Value = history.EndDate;
                IsLoading = false;

                RefreshGraphs();
            }

            // For 1024x600 netbooks, go ahead and maximize screen
            if (SystemInformation.VirtualScreen.Width == 1024 && SystemInformation.VirtualScreen.Height == 600)
                WindowState = FormWindowState.Maximized;
        }

        public void SetupTooltips()
        {
            System.Windows.Forms.ToolTip tip1 = new ToolTip();
            tip1.SetToolTip(btnRawExpendAll, "Show labels for all items");

            System.Windows.Forms.ToolTip tip2 = new ToolTip();
            tip2.SetToolTip(btnRawExpendOdd, "Show labels for Odd numbered items");

            System.Windows.Forms.ToolTip tip3 = new ToolTip();
            tip3.SetToolTip(btnRawExpendEven, "Show labels for Even numbered items");

        }

        #endregion

        #region Graphing Methods

        private void RefreshGraphs()
        {
            GraphActivity();
            RenderRawTransactionGraphs(0);
            RenderCategorizedGraph();
            UpdateStatistics();
        }

        private void SetupActivityGraph() 
        {

            GraphPane myPane = zedGraphControlActivity.GraphPane;
            myPane.Title.Text = "Chromatic Activity"; // +dateTimePicker1.Value.ToShortDateString() + " - " + dateTimePicker2.Value.ToShortDateString();
            myPane.XAxis.Title.Text = "Time";
            myPane.XAxis.Type = AxisType.Date;
            myPane.YAxis.Title.Text = "Fund Values";
            myPane.YAxis.Scale.Mag = 0;
            myPane.Fill = new Fill(Color.White, Color.Goldenrod, 45.0f);
            myPane.Chart.Fill = new Fill(Color.White, Color.Goldenrod, 45.0F);

        }

        private void SetupRawExpensesGraph()
        {
            GraphPane fdPane = zedGraphControlGroupByName.GraphPane;
            fdPane.Title.Text = "Expense Transactions (Grouped By Name)";
            fdPane.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.Chart.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.XAxis.IsVisible = false;
            fdPane.YAxis.IsVisible = false;
            fdPane.Legend.FontSpec.Size = 8f;
            fdPane.IsFontsScaled = false;
            fdPane.Legend.IsVisible = false;
            zedGraphControlGroupByName.IsShowPointValues = true;
            zedGraphControlGroupByName.IsEnableZoom = true;
            fdPane.Margin.Left = 0;
            fdPane.Margin.Right = 0;
            fdPane.Margin.Top = 0;
            fdPane.Margin.Bottom = 0;
        }

        private void SetupRawIncomeGraph()
        {
            GraphPane fdPane = zedGraphControlIncome.GraphPane;
            fdPane.Title.Text = "Income (Grouped By Name)";
            fdPane.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.Chart.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.XAxis.IsVisible = false;
            fdPane.YAxis.IsVisible = false;
            //fdPane.Legend.FontSpec.Size = 14f;
            fdPane.IsFontsScaled = false;
            fdPane.Legend.IsVisible = false;
            zedGraphControlIncome.IsShowPointValues = true;
        }

        private void SetupCategorizedGraph()
        {
            GraphPane fdPane = zedGraphControlCategorized.GraphPane;
            fdPane.Title.Text = "Income (Grouped By Name)";
            fdPane.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.Chart.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.XAxis.IsVisible = false;
            fdPane.YAxis.IsVisible = false;
            //fdPane.Legend.FontSpec.Size = 14f;
            fdPane.IsFontsScaled = false;
            fdPane.Legend.IsVisible = false;
            zedGraphControlCategorized.IsShowPointValues = true;
        }

        private void SetupCategorizedIncome()
        {
            GraphPane fdPane = zedGraphControlCategorizedIncome.GraphPane;
            fdPane.Title.Text = "Income (Grouped By Name)";
            fdPane.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.Chart.Fill = new Fill(Color.White, Color.Gray, 45.0F);
            fdPane.XAxis.IsVisible = false;
            fdPane.YAxis.IsVisible = false;
            //fdPane.Legend.FontSpec.Size = 14f;
            fdPane.IsFontsScaled = false;
            fdPane.Legend.IsVisible = false;
            zedGraphControlCategorizedIncome.IsShowPointValues = true;
        }

        private void GraphActivity()
        {
            //TimeSpan ts = EndDate - StartDate;
            GraphPane myPane = zedGraphControlActivity.GraphPane;
            myPane.CurveList.Clear();
            zedGraphControlActivity.IsShowPointValues = true;
            myPane.XAxis.Type = AxisType.Date;

            // Pad (only) a few extra days to scale so that it fills out the graph well
            //myPane.XAxis.Scale.Min = StartDate.AddDays(-ts.TotalDays / 14).ToOADate();
            //myPane.XAxis.Scale.Max = EndDate.AddDays(ts.TotalDays / 14).ToOADate();
            myPane.Title.Text = "Fund activity for " + history.Organization;
            myPane.YAxis.Scale.Mag = 0;

            string tooltip;

            int i = 0;

            PointPairList pplist = new PointPairList();

            Decimal RunningBalance = 0.0m;

            foreach (QFXTransaction trans in history.Transactions)
            {
                if (trans.Name == "ChromaticReconcile") RunningBalance = trans.TransactionAmount;
                else RunningBalance += trans.TransactionAmount;

                if (trans.DatePosted >= StartDate && trans.DatePosted <= EndDate)
                {

                    tooltip = RunningBalance.ToString() + "\n" + trans.Name + "\n" + trans.Memo;
                    pplist.Add(new PointPair(trans.DatePosted.ToOADate(), (double)RunningBalance, tooltip));

                    Color c = Color.Red;

                    SymbolType st = SymbolType.Triangle;
                }

            }

            LineItem myCurve = myPane.AddCurve(history.Organization, pplist, Color.Red, SymbolType.Triangle);

            zedGraphControlActivity.AxisChange();
            zedGraphControlActivity.Refresh();
        }

        private void UpdateStatistics()
        {
            lblNumberTransactions.Text = history.Transactions.Count.ToString();
            toolStripStatusLabelStats.Text = "Transactions : " + history.Transactions.Count.ToString();

            List<QFXNormalization> normalized = history.NormalizeCategoryTotals(dateTimePicker1.Value, dateTimePicker2.Value);
            normalized.Sort(new NormalizationComparer());

            dgvCategorizedAverages.DataSource = null;
            dgvCategorizedAverages.DataSource = normalized;

            List<QFXNormalization> normalized2 = history.NormalizeRawTransactions(dateTimePicker1.Value, dateTimePicker2.Value);
            normalized2.Sort(new NormalizationComparer());

            dgvRawAverages.DataSource = null;
            dgvRawAverages.DataSource = normalized2;


        }

        Color IndexColor(int ColorIndex)
        {
            Color c = Color.Blue;
            switch (ColorIndex)
            {
                case 0: c = Color.Red; break;
                case 1: c = Color.Lime; break;
                case 2: c = Color.Blue; break;
                case 3: c = Color.Firebrick; break;
                case 4: c = Color.MediumSeaGreen; break;
                case 5: c = Color.Yellow; break;
                case 6: c = Color.MediumPurple; break;
                case 7: c = Color.DarkKhaki; break;
                case 8: c = Color.Indigo; break;
                case 9: c = Color.Red; break;
                case 10: c = Color.Lime; break;
                case 11: c = Color.Blue; break;
                case 12: c = Color.Firebrick; break;
                case 13: c = Color.MediumSeaGreen; break;
                case 14: c = Color.Yellow; break;
                case 15: c = Color.MediumPurple; break;
                case 16: c = Color.DarkKhaki; break;
                case 17: c = Color.Indigo; break;
                case 18: c = Color.Red; break;
                case 19: c = Color.Lime; break;
                case 20: c = Color.Blue; break;
                case 21: c = Color.Firebrick; break;
                case 22: c = Color.MediumSeaGreen; break;
                case 23: c = Color.Yellow; break;
                case 24: c = Color.MediumPurple; break;
                case 25: c = Color.DarkKhaki; break;
                case 26: c = Color.Indigo; break;
                case 27: c = Color.Red; break;
                case 28: c = Color.Lime; break;
                case 29: c = Color.Blue; break;
                case 30: c = Color.Firebrick; break;
                case 31: c = Color.MediumSeaGreen; break;
                case 32: c = Color.Yellow; break;
                case 33: c = Color.MediumPurple; break;
                case 34: c = Color.DarkKhaki; break;
                case 35: c = Color.Indigo; break;
                default: break;
            }

            return c;
        }

        private void RenderRawTransactionGraphs(int Mode)
        {
            GraphPane myPane = zedGraphControlGroupByName.GraphPane;
            myPane.CurveList.Clear();
            myPane.Title.Text = "Transactions (Grouped By Name)";

            GraphPane incomePane = zedGraphControlIncome.GraphPane;
            incomePane.CurveList.Clear();
            incomePane.Title.Text = "Income (Grouped By Name)";

            if (history.Transactions.Count == 0) return;

            int ColorIndex = 0;

            PointPairList pplist = new PointPairList();

            Dictionary<string, Decimal> GroupedTotals = history.GroupTransactionsByName(StartDate, EndDate);
            foreach (KeyValuePair<string, Decimal> kvp in GroupedTotals)
            {
                bool ShowLabel = false;

                if ((Mode == 0) || (Mode == 1 && (ColorIndex + 1) % 2 == 1) || (Mode == 2 && (ColorIndex + 1) % 2 == 0))
                    ShowLabel = true;

                Color c = IndexColor(ColorIndex++);
                Decimal amt = kvp.Value;

                if (kvp.Key != "ChromaticReconcile") {
                    if (amt < 0)
                    {
                        PieItem segment1 = myPane.AddPieSlice((Double)Math.Abs(amt), c, Color.White, 45f, 0, ShowLabel?kvp.Key:"");
                    }
                    else 
                    {
                        PieItem segment1 = incomePane.AddPieSlice((Double)Math.Abs(amt), c, Color.White, 45f, 0, kvp.Key);
                    }
                }
            }

            zedGraphControlGroupByName.AxisChange();
            zedGraphControlGroupByName.Refresh();

            zedGraphControlIncome.AxisChange();
            zedGraphControlIncome.Refresh();
        }

        private void RenderCategorizedGraph()
        {
            GraphPane myPane = zedGraphControlCategorized.GraphPane;
            myPane.CurveList.Clear();
            myPane.Title.Text = "Expenditures (Grouped By Category)";

            GraphPane incomePane = zedGraphControlCategorizedIncome.GraphPane;
            incomePane.CurveList.Clear();
            incomePane.Title.Text = "Income (Grouped By Category)";

            if (history.Transactions.Count == 0) return;

            int ColorIndex = 0;

            List<string> cats = new List<string>();
            cats.Add("");
            cats.AddRange(history.Categories);

            foreach (string CategoryName in cats) 
            {
                Decimal amt = history.TotalCategory(CategoryName, StartDate, EndDate);

                Color c = IndexColor(ColorIndex++);

                if (amt < 0)
                {
                    PieItem segment1 = myPane.AddPieSlice((Double) (amt * -1), c, Color.White, 45f, 0, CategoryName==""?"Uncategorized":CategoryName);
                }
                else
                {
                    PieItem segment1 = incomePane.AddPieSlice((Double)amt, c, Color.White, 45f, 0, CategoryName == "" ? "Uncategorized" : CategoryName);
                }
            }

            zedGraphControlCategorized.AxisChange();
            zedGraphControlCategorized.Refresh();

            zedGraphControlCategorizedIncome.AxisChange();
            zedGraphControlCategorizedIncome.Refresh();
        }

        #endregion

        #region Menu Handlers

        private void mnuiExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void mnuiImportQFX_Click(object sender, EventArgs e)
        {
            openFileDialog1.DefaultExt = ".qfx";
            openFileDialog1.FileName = "";
            openFileDialog1.Filter = "Quicken Files|*.qfx";

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                import = new QFXHistory();
                import.ParseFile(openFileDialog1.FileName);

                if (history.Transactions.Count > 0)
                {
                    history.Merge(import);
                    history.SaveHistoryX();
                }
                else
                {
                    import.Categories = history.Categories;  // retain any categories
                    history = import;
                    import = new QFXHistory();
                    history.SaveHistoryX();

                    dateTimePicker1.Value = history.StartDate;
                    dateTimePicker2.Value = history.EndDate;
                }

                RefreshGraphs();

                MessageBox.Show("History Imported and saved.", "Import Completed", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }

        private void mnuiEditCategories_Click(object sender, EventArgs e)
        {
            EditCategories ec = new EditCategories();
            ec.ShowDialog();

            history.SaveHistoryX();

            RefreshGraphs();
        }

        private void mnuiTransactionHistory_Click(object sender, EventArgs e)
        {
            ViewTransactions vt = new ViewTransactions();
            vt.ShowDialog();

            history.SaveHistoryX();

            RefreshGraphs();

        }

        private void mnuiDeleteTransactions_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure you want to delete transaction history?", "Confirm deletion of Transaction History", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) return;

            history.Transactions.Clear();
            history.AccountID = "";
            history.AccountType = "";
            history.Balance = 0.0m;
            history.BalanceDate = DateTime.MinValue;
            history.BankID = "";
            history.Currency = "";
            history.EndDate = DateTime.MinValue;
            history.IntuitBankID = "";
            history.Organization = "";
            history.StartDate = DateTime.MinValue;

            history.SaveHistoryX();

            RefreshGraphs();
        }

        private void mnuiHelpAbout_Click(object sender, EventArgs e)
        {
            AboutForm af = new AboutForm();
            af.ShowDialog();
        }

        private void mnuiZoomGraph_Click(object sender, EventArgs e)
        {
            pnlTop.Visible = !pnlTop.Visible;
        }

        #endregion

        #region Button Handlers

        private void btnToggleZoom_Click(object sender, EventArgs e)
        {
            pnlRight.Visible = !pnlRight.Visible;
        }

        private void btnFullscreen_Click(object sender, EventArgs e)
        {

        }

        private void btnRawExpendAll_Click(object sender, EventArgs e)
        {
            RenderRawTransactionGraphs(0);
        }

        private void btnRawExpendOdd_Click(object sender, EventArgs e)
        {
            RenderRawTransactionGraphs(1);
        }

        private void btnRawExpendEven_Click(object sender, EventArgs e)
        {
            RenderRawTransactionGraphs(2);
        }

        private void btnHideToolbar_Click(object sender, EventArgs e)
        {
            pnlTop.Visible = false;
        }

        #endregion

        #region DateTime Trim Events

        private void btnStartYdec_Click(object sender, EventArgs e)
        {
            dateTimePicker1.Value = dateTimePicker1.Value.AddYears(-1);

            RefreshGraphs();
        }

        private void btnStartMdec_Click(object sender, EventArgs e)
        {
            dateTimePicker1.Value = dateTimePicker1.Value.AddMonths(-1);

            RefreshGraphs();
        }

        private void btnStartMinc_Click(object sender, EventArgs e)
        {
            dateTimePicker1.Value = dateTimePicker1.Value.AddMonths(1);

            RefreshGraphs();
        }

        private void btnStartYinc_Click(object sender, EventArgs e)
        {
            dateTimePicker1.Value = dateTimePicker1.Value.AddYears(1);

            RefreshGraphs();
        }

        private void btnEndYdec_Click(object sender, EventArgs e)
        {
            dateTimePicker2.Value = dateTimePicker2.Value.AddYears(-1);

            RefreshGraphs();
        }

        private void btnEndMdec_Click(object sender, EventArgs e)
        {
            dateTimePicker2.Value = dateTimePicker2.Value.AddMonths(-1);

            RefreshGraphs();
        }

        private void btnEndMinc_Click(object sender, EventArgs e)
        {
            dateTimePicker2.Value = dateTimePicker2.Value.AddMonths(1);

            RefreshGraphs();
        }

        private void btnEndYinc_Click(object sender, EventArgs e)
        {
            dateTimePicker2.Value = dateTimePicker2.Value.AddYears(1);

            RefreshGraphs();
        }

        private void dateTimePicker2_ValueChanged(object sender, EventArgs e)
        {
            if (IsLoading) return;

            RefreshGraphs();
        }

        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            if (IsLoading) return;

            RefreshGraphs();
        }

        #endregion

        private void mnuiOnlineHelp_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.UseShellExecute = true;
            proc.StartInfo.FileName = "http://project-continuum.com/OnlineHelp/ChromaticQFX.aspx";
            proc.Start();
        }

    }
}
